#include "encoder_functions.h"

// G = RS_GENERATOR(M, ADD_ONE, T)  Create a generator for a t-error
// correcting Reed-Solomon code, using the provided add-one table for
// GF(2^m).
//
//  Inputs:
//         m        Galois Field order: GF(2^m)
//         add_one  Add-one table for the field
//         t        Error-correcting capacity of the code
//
//  Output:
//         G   RS code generator polynomial
//
//  Notes:
//
// The values of t and m are specified as global variables in init.m

Vector * RS_generator(int m, Matrix * add_one, int t) {
    Vector *g, *poly, *temp;
    int i;

    g = allocate_vector(1);
    g->data[0] = 0;

    // t-error correcting --> multiply 2t consecutive (x-a^n) terms
    for (i = 0; i < 2*t; i++) {
        
        poly = allocate_vector(2);
        poly->data[0] = i+1;
        poly->data[1] = 0;
       
        temp = polyMult(m, add_one, g,poly);
        free_vector(g);
        g = temp;

        free_vector(poly);

    }

    return g;

}

// T = RS_ENCODER(DATA) Given a data sequence, encode a Reed-Solomon code 
//                      word.
//
//  Input
//         DATA  Data word to be encoded
//
//  Output
//         T    Code word to be transmitted
//
//  Notes
//
//  The values of t and m are specified as global variables in init.m

Vector * RS_encoder(int m, Matrix * add_one, int t, Vector * D, Vector * g) {

    Vector *T, *M, *xnmk, *M_xnmk;
    Vector **qr;
    int i;
    int n, k; 

    // The data symbols are the coefficients of the message polynomial
    M = copy_vector(D);
    for (i = 0; i < ((M->len)>>1); i++) {
        swap(M->data[i], M->data[M->len-1-i]); 
    }

    // Form x^(n-k)
    n = (1<<m) - 1;
    k = n - 2*t;
    xnmk = allocate_vector(n-k+1);

    for (i = 0; i < xnmk->len - 1; i++) {
        xnmk->data[i] = -1;
    }
    xnmk->data[i] = 0;

    // The transmitted word T is ( M(x) * x^(n-k) ) / g(x)
    M_xnmk = polyMult(m, add_one, M, xnmk);
    qr = polyDiv(m, add_one, M_xnmk, g);
    T = polyAdd(m, add_one, M_xnmk, qr[1]);

    // Free up all of the temp variables
    free_vector(xnmk);
    free_vector(M_xnmk);
    free_vector(M);
    free_vector(qr[0]);
    free_vector(qr[1]);
    free(qr);

    return T;

}


